# 创建时间:2023/2/11 18:31
# 创建人:天霄
# 计划 :SenjoTwintail
# 文件 :PlayMusic.py
# 基于 Python 3.8.2
# ========================================
# 音乐播放
# ========================================
from typing import Dict

import pygame

# pygame.mixer.init() 或者只初始化音频部分
# pygame.mixer.music.load('xx.mp3') 使用文件名作为参数载入音乐,音乐可以是ogg、mp3等格式。
#           载入的音乐不会全部放到内容中，而是以流的形式播放的，即在播放的时候才会一点点从文件中读取。
# pygame.mixer.music.play()播放载入的音乐。该函数立即返回，音乐播放在后台进行。
#           play方法还可以使用两个参数
#           pygame.mixer.music.play(loops=0, start=0.0) loops和start分别代表重复的次数和开始播放的位置。
# pygame.mixer.music.stop() 停止播放，
# pygame.mixer.music.pause() 暂停播放。
# pygame.mixer.music.unpause() 取消暂停。
# pygame.mixer.music.fadeout(time) 用来进行淡出，在time毫秒的时间内音量由初始值渐变为0，最后停止播放。
# pygame.mixer.music.set_volume(value) 来设置播放的音量，音量value的范围为0.0到1.0。
# pygame.mixer.music.get_busy() 判断是否在播放音乐,返回1为正在播放。
# pygame.mixer.music.get_volume() 获取音量大小。
# pygame.mixer.music.get_pos()    获取播放的时长，单位毫秒
# pygame.mixer.music.set_endevent(pygame.USEREVENT + 1) 在音乐播放完成时，用事件的方式通知用户程序，
#           设置当音乐播放完成时发送pygame.USEREVENT+1事件给用户程序。
# pygame.mixer.music.queue(filename) 使用指定下一个要播放的音乐文件，当前的音乐播放完成后自动开始播放指定的下一个。
#           一次只能指定一个等待播放的音乐文件。
from Api import savings

pySound = pygame.mixer.Sound


class Musics:
    """播放一个音乐"""
    def __init__(self):
        self.music_dict = dict()
        self._key_number = 0

    def __del__(self):
        del self.music_dict
        del self._key_number

    def add(self, musicfile, key=None):
        """添加音频

        :param musicfile: 音频文件
        :param key: 为音频设置唯一值以进行索引，若重复则抛错
        :return: 该音频对象(可播放)，key
        """
        if key in self.music_dict:
            raise KeyError(f'键”{key}“已存在！当前键：{self.music_dict.keys()}')
        elif key is None:
            self._key_number += 1
            key = '_'.join(['key', str(self._key_number)])
        self.music_dict[key] = musicfile
        return key

    def remove(self, key):
        """移除音频并停止播放"""
        if key not in self.music_dict:
            raise KeyError(f'键”{key}“不存在！当前键：{self.music_dict.keys()}')
        pygame.mixer.music.stop()
        self.music_dict.pop(key)
        self._key_number -= 1

    def change(self, key, musicfile):
        """替换音频并停止播放"""
        if key not in self.music_dict:
            raise KeyError(f'键”{key}“不存在！当前键：{self.music_dict.keys()}')
        pygame.mixer.music.stop()
        self.music_dict[key] = musicfile

    def clear(self):
        """清空音频、停止播放"""
        pygame.mixer.music.stop()
        self.music_dict.clear()
        self._key_number = 0

    def get(self, key):
        """获取音频的路径"""
        if key not in self.music_dict:
            raise KeyError(f'键”{key}“不存在！当前键：{self.music_dict.keys()}')
        musicfile: str = self.music_dict[key]
        return musicfile

    def play(self, key, loops=0, maxtime=0, fade_ms=0, voice=savings.voice_soldier):
        """指定类内播放

        :param key: 指定的音乐
        :param loops: 循环次数，-1即无限循环
        :param maxtime: 播放指定时长后停止，毫秒
        :param fade_ms: 以零音量逐渐提升的毫秒数
        :param voice: 音量，默认为设置项中的军士音量
        :return:
        """
        if key not in self.music_dict:
            raise KeyError(f'键”{key}“不存在！当前键：{self.music_dict.keys()}')
        music = self.get(key)
        pygame.mixer.music.load(music)
        pygame.mixer.music.set_volume(voice/100)
        pygame.mixer.music.play(loops, maxtime, fade_ms)

    def playMusic(self, musicPath, loops=0, maxtime=0, fade_ms=0, voice=savings.voice_soldier):
        """指定文件进行播放

        :param key: 指定的音乐文件路径
        :param loops: 循环次数，-1即无限循环
        :param maxtime: 播放指定时长后停止，毫秒
        :param fade_ms: 以零音量逐渐提升的毫秒数
        :param voice: 音量，默认为设置项中的军士音量
        :return:
        """
        pygame.mixer.music.load(musicPath)
        pygame.mixer.music.set_volume(voice/100)
        pygame.mixer.music.play(loops, maxtime, fade_ms)

    def stop(self):
        """停止播放"""
        pygame.mixer.music.stop()

    def pause(self):
        """指定暂停播放"""
        pygame.mixer.music.pause()

    def fadeout(self, time):
        """指定淡出播放"""
        pygame.mixer.music.fadeout(time)


class Sounds:
    """可同时播放音频"""
    def __init__(self, music_only=False):
        """请在初始化后进行实例化，否则请按仅音频模式实例化"""
        if not music_only:
            pygame.mixer.init()
        self.sound_dict: Dict[str, str] = {}
        self.keys = list()
        self.chancel_dict: Dict[str, pygame.mixer.Channel] = {}
        self._count = 0

    def __del__(self):
        del self.sound_dict
        del self.keys
        del self._count

    def add(self, soundfile, key=None):
        """添加音频

        :param soundfile: 音频文件
        :param key: 为音频设置唯一值以进行索引，若重复则抛错
        :return: key
        """
        if key in self.sound_dict:
            raise KeyError(f'键”{key}“已存在！当前键：{self.sound_dict.keys()}')
        elif key is None:
            key = '_'.join(['key', str(self._count)])
        self._count += 1
        self.keys.append(key)
        self.sound_dict[key] = soundfile
        return key

    def remove(self, key):
        """移除音频"""
        if key not in self.sound_dict:
            raise KeyError(f'键”{key}“不存在！当前键：{self.sound_dict.keys()}')
        self.stop(key)
        self.sound_dict.pop(key)
        self.keys.remove(key)
        self._count -= 1

    def change(self, key, soundfile):
        """替换音频"""
        if key not in self.sound_dict:
            raise KeyError(f'键”{key}“不存在！当前键：{self.sound_dict.keys()}')
        self.stop(key)
        self.sound_dict[key] = soundfile

    def clear(self):
        """清空音频"""
        self.stop_all()
        self.sound_dict.clear()
        self.keys.clear()
        self._count = 0

    def getSound(self, key, voice=100):
        """获取音频对象"""
        if key not in self.sound_dict:
            raise KeyError(f'键”{key}“不存在！当前键：{self.sound_dict.keys()}')
        sound = pySound(self.sound_dict[key])
        sound.set_volume(voice/100)
        return sound

    def play_all(self, loops=0, maxtime=0, fade_ms=0, voice=100):
        """播放全部

        :param key: 指定的音乐
        :param loops: 循环次数，-1即无限循环
        :param maxtime: 播放指定时长后停止，毫秒
        :param fade_ms: 以零音量逐渐提升的毫秒数
        :param voice: 音量
        :return:
        """
        self.chancel_dict.clear()
        for key in self.sound_dict.keys():
            sound = pySound(self.sound_dict[key])
            sound.set_volume(voice/100)
            sound.set_volume(voice/100)
            channel = sound.play(loops, maxtime, fade_ms)
            self.chancel_dict[key] = channel

    def play(self, key, loops=0, maxtime=0, fade_ms=0, voice=100):
        """指定播放

        :param key: 指定的音乐
        :param loops: 循环次数，-1即无限循环
        :param maxtime: 播放指定时长后停止，毫秒
        :param fade_ms: 以零音量逐渐提升的毫秒数
        :param voice: 音量
        :return:
        """
        if key not in self.sound_dict:
            raise KeyError(f'键”{key}“不存在！当前键：{self.sound_dict.keys()}')
        soundfile = self.sound_dict[key]
        sound = pySound(soundfile)
        sound.set_volume(voice/100)
        channel = sound.play(loops, maxtime, fade_ms)
        self.chancel_dict[key] = channel
        return sound

    def stop_all(self):
        """停止播放全部"""
        for key in self.chancel_dict.keys():
            self.chancel_dict[key].stop()
        self.chancel_dict.clear()

    def stop(self, key):
        """指定停止播放"""
        if key in self.chancel_dict.keys():
            self.chancel_dict[key].stop()
            self.chancel_dict.pop(key)

    def pause_all(self):
        """暂停播放全部"""
        for key in self.chancel_dict.keys():
            self.chancel_dict[key].pause()

    def pause(self, key):
        """指定暂停播放"""
        if key in self.chancel_dict.keys():
            self.chancel_dict[key].pause()

    def fadeout_all(self, time):
        """淡出播放全部"""
        for key in self.chancel_dict.keys():
            self.chancel_dict[key].fadeout(time)

    def fadeout(self, key, time):
        """指定淡出播放"""
        if key in self.chancel_dict.keys():
            self.chancel_dict[key].fadeout(time)



